﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Statistics.Distribution
{
    /// <summary>
    /// This class represents a Yule-Simon distribution.
    /// </summary>
    [Serializable]
    public class YuleSimonDistribution
    {
        /// <summary>
        /// The shape parameter of the distribution.
        /// </summary>
        private readonly double shape;

        /// <summary>
        /// Initializes a new instance of the <see cref="YuleSimonDistribution"/> class.
        /// </summary>
        /// <param name="shape">The shape parameter of the distribution.</param>
        public YuleSimonDistribution(double shape)
        {
            this.shape = shape;
        }

        /// <summary>
        /// Gets the shape parameter of the distribution.
        /// </summary>
        /// <value>The shape parameter of the distribution.</value>
        public double Shape
        {
            get { return this.shape; }
        }

        /// <summary>
        /// Gets the mean of the distribution.
        /// </summary>
        /// <value>The mean of the distribution.</value>
        public double Mean
        {
            get
            {
                if (this.shape > 1)
                {
                    return this.shape/(this.shape - 1);
                }

                return 0;
            }
        }

        /// <summary>
        /// Gets the mode of the distribution.
        /// </summary>
        /// <value>The mode of the distribution.</value>
        public double Mode
        {
            get { return 1; }
        }

        /// <summary>
        /// Gets the variance of the distribution.
        /// </summary>
        /// <value>The variance of the distribution.</value>
        public double Variance
        {
            get
            {
                if (this.shape > 2)
                {
                    return (this.shape*this.shape)/(Math.Pow(this.shape - 1, 2)*(this.shape - 2));
                }

                return 0;
            }
        }

        /// <summary>
        /// Gets the skewness of the distribution.
        /// </summary>
        /// <value>The skewness of the distribution.</value>
        public double Skewness
        {
            get
            {
                if (this.shape > 3)
                {
                    return (Math.Pow(this.shape + 1, 2)*Math.Sqrt(this.shape - 2))/(this.shape*(this.shape - 3));
                }

                return 0;
            }
        }

        /// <summary>
        /// Computes the probability mass function of the Yule-Simon distribution at the specified postion k.
        /// </summary>
        /// <param name="k">The specified position k.</param>
        /// <returns>
        /// The probability mass function of the Yule-Simon distribution at the specified postion k.
        /// </returns>
        public double ProbabilityMassFunction(uint k)
        {
            return this.shape*SpecialFunctions.BetaFunction(k, this.shape + 1);
        }

        /// <summary>
        /// Computes the cumulative distribution function of the Yule-Simon distribution at the specified postion k.
        /// </summary>
        /// <param name="k">The specified position k.</param>
        /// <returns>
        /// The cumulative distribution function of the Yule-Simon distribution at the specified postion k.
        /// </returns>
        public double CumulativeDistributionFunction(uint k)
        {
            return 1 - k*SpecialFunctions.BetaFunction(k, this.shape + 1);
        }
    }
}